package com.ke.rule.base;

import com.google.common.collect.Maps;
import org.springframework.beans.factory.parsing.Problem;

import java.util.*;

public class BusinessException extends RuntimeException {
  private static final long serialVersionUID = -578404355428117470L;
  
  protected static final String ARG_KEY_PROBLEMS = "problems";
  protected Set<String> ignoreWarnCodes = new HashSet<>();
  private String code;
  private Boolean isRelated;
  /**
   * 批次索引，用于批量操作时，标识当前批次的索引, 从0开始
   */
  private Integer batchIndex;
  private String objectId;
  
  /**
   * 参数, 以KV方式提供，有序的map, 
   * 如果code对应的错误码有替换变量，则以args中的值进行替换，
   * 其中${MESSAGE}为特殊替换变量，表示将异常的message替换
   */
  protected LinkedHashMap<String, Object> args;

  public BusinessException(Throwable cause) {
    super(cause);
    this.code = ExceptionCodes.UNKNOWN_ERROR;
  }

  public BusinessException(String code, String message) {
    super(message);
    this.code = code;
  }
  
  public BusinessException(String code, String message, LinkedHashMap<String, Object> args) {
    super(message);
    this.code = code;
    this.args = args;
  }
  
  public BusinessException(String code, String message, String argKey, Object argValue) {
    this(code, message);
    this.args = Maps.newLinkedHashMap();
    args.put(argKey, argValue);
  }
  
  public BusinessException(String code, String message, String argKey1, Object argValue1, String argKey2, Object argValue2) {
    this(code, message, argKey1, argValue1);
    args.put(argKey2, argValue2);
  }

  public BusinessException(String code, String message, Throwable cause) {
    super(message, cause);
    this.code = code;
  }

  public String getCode() {
    return code;
  }

  public LinkedHashMap<String, Object> getArgs() {
    return args;
  }

  public void setArgs(LinkedHashMap<String, Object> args) {
    this.args = args;
  }
  
  /**
   * 是否为相关对象引起的问题， 如果为true, 前端显示时，默认只显示一次
   * @return
   */
  public Boolean getIsRelated() {
    return isRelated;
  }

  /**
   * 设置是否为相关对象引起的问题， 如果为true, 前端显示时，默认只显示一次
   * @param isRelated
   */
  public void setIsRelated(Boolean isRelated) {
    this.isRelated = isRelated;
  }

  public Set<String> getIgnoreWarnCodes() {
    return ignoreWarnCodes;
  }

  /**
   * 存在问题吗？
   * @return
   */
  public boolean anyProblems() {
    return null != args && args.containsKey(ARG_KEY_PROBLEMS);
  }
  
  /**
   * 获取可能存在的问题列表
   * @return 问题列表, maybe null
   */
  @SuppressWarnings("unchecked")
  public List<Problem> getProblems() {
    if (null == args) {
      return null;
    }
    Map<String, Map<ProblemTypeEnum, List<Problem>>> groupByName = (Map<String, Map<ProblemTypeEnum, List<Problem>>>) args.get(ARG_KEY_PROBLEMS);
    if (null == groupByName) {
      return null;
    }
    List<Problem> problems = new ArrayList<>();
    groupByName.values().stream()
      .forEach(m -> m.values().stream().forEach(list -> problems.addAll(list)));
    
    return problems;
  }

  public Integer getBatchIndex() {
    return batchIndex;
  }

  public void setBatchIndex(Integer batchIndex) {
    this.batchIndex = batchIndex;
  }

  public String getObjectId() {
    return objectId;
  }

  public void setObjectId(String objectId) {
    this.objectId = objectId;
  }
}
